#include <cstdint>

using namespace std;

namespace rts
{
#pragma pack(push)
#pragma pack(1)
struct CommonFragmentHeader
{
    uint8_t version : 4;

    // 0: RtsRegularFragmentHeader
    // 1: RtsAckFragmentHeader
    // 2: RtsFecFragmentHeader
    uint8_t hdr_type  : 4;
    uint8_t is_traced : 1;
    uint8_t needs_ack : 1;

    // 0: one2one
    // 1: one2many
    uint16_t msg_type     : 5;
    uint16_t payload_size : 11;
    uint64_t msg_id;
};

struct RegularFragmentHeader
{
    CommonFragmentHeader cmn_hdr;
    uint16_t             total_of_fragments;
    uint16_t             fragment_sequence_number; // [0, infinite)
    uint8_t              total_of_options;
};

struct FecFragmentHeader
{
    CommonFragmentHeader cmn_hdr;
    uint16_t             total_of_packets;
    uint16_t             parket_sequence_number;
    uint16_t             packet_size;
    uint8_t              total_of_data_blocks;
    uint8_t              total_of_fec_blocks;
    uint8_t              block_sequence_number; // [0, total_of_blocks)
    uint8_t              total_of_options;
};

struct AckFragmentHeader
{
    CommonFragmentHeader cmn_hdr;
    int32_t              error_code;
};

struct StdId
{
    uint8_t length; // The total of elements in array `id`.
    uint8_t id[];
};

using AppId = StdId;
using SrcId = StdId;
using DstId = StdId;

struct CompressionOption
{
    uint8_t option_type; // Must be 1.
    uint8_t compression_method;
};

struct CryptoOption
{
    uint8_t option_type; // Must be 2.
    uint8_t crypto_method;
};

struct ReliabilityOption
{
    uint8_t  option_type;       // Must be 3.
    uint8_t  reliability_level; // [1, 100]
    uint32_t session_id;
    uint32_t sequence_number; // [0, infinite)
};

struct MissingMessagesOption
{
    uint8_t  option_type; // Must be 4.
    uint32_t session_id;
    uint8_t  total_of_sequence_numbers;
    uint32_t sequence_numbers[];
};

#pragma pack(pop)
} // namespace rts